package com.dk.shared.autoconfigure.common;

import com.dk.common.feign.FeignDecoder;
import com.dk.common.utils.SpringUtil;
import com.dk.shared.executor.CommonTaskExecutor;
import feign.codec.Decoder;
import feign.optionals.OptionalDecoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan;
import org.springframework.cloud.openfeign.support.HttpMessageConverterCustomizer;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.EventListener;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.client.RestTemplate;

@EnableAsync
@Import(WebMVCConfiguration.class)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({SharedProperties.class})
@RemoteApplicationEventScan(basePackages = "com.dk.shared.events")
@AutoConfigureAfter(TransactionAutoConfiguration.class)
public class SharedAutoConfiguration {

    @Autowired
    private  SharedProperties sharedProperties;

    @Bean
    @ConditionalOnMissingBean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @EventListener(ApplicationReadyEvent.class)
    public void onReady(ApplicationReadyEvent readyEvent) {
        SpringUtil.setApplicationContext(readyEvent.getApplicationContext());
    }

    @Bean("transactionWithNew")
    @ConditionalOnBean(PlatformTransactionManager.class)
    @ConditionalOnMissingBean(name = "transactionWithNew")
    public TransactionTemplate transactionWithNew(PlatformTransactionManager transactionManager) {
        return new TransactionTemplate(transactionManager, new DefaultTransactionDefinition(TransactionDefinition
                .PROPAGATION_REQUIRES_NEW));
    }


    @Bean
    @ConditionalOnMissingBean(Decoder.class)
    public Decoder feignDecoder(ObjectFactory<HttpMessageConverters> msgConverters,
                                ObjectProvider<HttpMessageConverterCustomizer> customizers) {
        FeignDecoder feignDecoder = new FeignDecoder(
                new SpringDecoder(msgConverters, customizers));
        ResponseEntityDecoder responseEntityDecoder = new ResponseEntityDecoder(feignDecoder);
        return new OptionalDecoder(responseEntityDecoder);
    }

    @Bean
    @ConditionalOnMissingBean
    public CommonTaskExecutor commonTaskExecutor(ThreadPoolTaskExecutor executor) {
        return new CommonTaskExecutor(executor);
    }

    @Bean
    @ConditionalOnMissingBean
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder){
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        restTemplateBuilder.additionalMessageConverters(messageConverter);
        return  restTemplateBuilder.build();
    }

/*    @Bean
    @Primary
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer(
            @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}") String pattern) {
        //TODO
        return jacksonObjectMapperBuilder -> {
            jacksonObjectMapperBuilder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern)));
            jacksonObjectMapperBuilder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(pattern)));
        };
    }*/
}
